package app.auto.runner.base.framework;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Color;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;
import java.util.TreeSet;

import app.auto.runner.base.ActivityPool;
import app.auto.runner.base.DialogUtil;
import app.auto.runner.base.DialogUtil.DialogInfo;
import app.auto.runner.base.Logs;
import app.auto.runner.base.SPrefUtil;
import app.auto.runner.base.intf.FunCallback;
import app.auto.runner.base.ui.highlight.TextHighLightDecorator;
import app.auto.runner.base.utility.HandlerUtil;
import app.auto.runner.base.utility.ReadFileUtil;
import app.auto.runner.base.utility.SerialUtil;
import app.auto.runner.base.utility.StorageUtil;
import app.auto.runner.base.utility.ToastUtil;
import app.auto.runner.base.utility.WriteFileUtil;


/**
 * 错误处理类
 */
public class CrashHandler implements UncaughtExceptionHandler {
    /**
     * Debug Log tag
     */
    public static final String TAG = "CrashHandler";
    /**
     * */
    public static final boolean DEBUG = true;
    //系统默认的UncaughtException处理类
    private UncaughtExceptionHandler mDefaultHandler;
    //CrashHandler实例
    private static CrashHandler INSTANCE;
    //程序的Context对象
    private static Context mContext;
    //用来保存配置信息
    private Properties mDeviceCrashInfo = new Properties();
    private static final String VERSION_NAME = "versionName";
    private static final String VERSION_CODE = "versionCode";
    private static final String STACK_TRACE = "STACK_TRACE";
    private static final String CRASH_REPORTER_EXTENSION = ".cr";
    private boolean debug = true;

    public CrashHandler() {
    }

    public static CrashHandler getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new CrashHandler();
        }
        return INSTANCE;
    }

    public boolean test;

    public CrashHandler setTest(boolean test) {
        this.test = test;
        return this;
    }

    /**
     * @param ctx
     */

    public void init(Context ctx) {
        //获取系统默认的UncaughtException处理器
        if (mDefaultHandler == null) {
            if (ctx instanceof Activity) {
                ActivityPool.currAty = (Activity) ctx;
            }
            mContext = ctx;
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
            Thread.setDefaultUncaughtExceptionHandler(this);
            SerialUtil.initCtx(mContext);
            SPrefUtil.iniContext(mContext);
        }

        if (!errorDialog("")) {
            if (test) {
                throw new RuntimeException("testing effect");
            }
        }

    }

    /**
     * @param ex
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return true;
        }
        final String msg = ex.getLocalizedMessage();
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                // Toast.LENGTH_LONG)
                // .show();
                Looper.loop();
            }

        }.start();
        collectCrashDeviceInfo(mContext);
        String crashFileName = saveCrashInfoToFile(ex);
        sendCrashReportsToServer(mContext);
        return true;
    }

    /**
     */
    public void sendPreviousReportsToServer() {
        sendCrashReportsToServer(mContext);
    }

    /**
     * @param ctx
     */
    private void sendCrashReportsToServer(Context ctx) {
        String[] crFiles = getCrashReportFiles(ctx);
        if (crFiles != null && crFiles.length > 0) {
            TreeSet<String> sortedFiles = new TreeSet<String>();
            sortedFiles.addAll(Arrays.asList(crFiles));

            for (String fileName : sortedFiles) {
                File cr = new File(ctx.getFilesDir(), fileName);
                postReport(cr);
                cr.delete();
            }
        }
    }

    private void postReport(File file) {
    }

    /**
     * @param ctx
     * @return
     */
    private String[] getCrashReportFiles(Context ctx) {
        File filesDir = ctx.getFilesDir();
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(CRASH_REPORTER_EXTENSION);
            }
        };
        return filesDir.list(filter);
    }

    /**
     * @param ex
     * @return
     */
    private String saveCrashInfoToFile(Throwable ex) {
        Writer info = new StringWriter();
        PrintWriter printWriter = new PrintWriter(info);
        ex.printStackTrace(printWriter);

        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }

        String result = info.toString();
        printWriter.close();
        mDeviceCrashInfo.put(STACK_TRACE, result);

        try {
            long timestamp = System.currentTimeMillis();
            if (Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) {
                File mk = new File("/sdcard/Jibo/Error/");
                if (!mk.exists()) {
                    mk.mkdirs();
                }
                String fileName = "/sdcard/Jibo/Error/" + timestamp + ".log";
                File ErrorLog = new File(fileName);
                if (!ErrorLog.exists()) {
                    ErrorLog.createNewFile();
                }
                FileWriter fw = new FileWriter(ErrorLog, true);
                BufferedWriter bw = new BufferedWriter(fw);
                bw.write((new Date(timestamp)).toLocaleString() + "\r\naaaa"
                        + ex.getLocalizedMessage() + "\r\nbbbbbb:"
                        + mDeviceCrashInfo.getProperty(STACK_TRACE));
                bw.close();
                fw.close();
                return fileName;
            }
        } catch (Exception e) {
            Log.e(TAG, "an error occured while writing report file...", e);
        }
        return null;
    }

    /**
     * @param ctx
     */
    public void collectCrashDeviceInfo(Context ctx) {
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
                    PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                mDeviceCrashInfo.put(VERSION_NAME,
                        pi.versionName == null ? "not set" : pi.versionName);
                mDeviceCrashInfo.put(VERSION_CODE, pi.versionCode);
            }
        } catch (NameNotFoundException e) {
            Log.e(TAG, "Error while collect package info", e);
        }
        Field[] fields = Build.class.getDeclaredFields();//getDeclaredFields()只能获取自己声明的各种字段，包括public，protected，private
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                mDeviceCrashInfo.put(field.getName(), field.get(null));
                if (DEBUG) {
                    Log.d(TAG, field.getName() + " : " + field.get(null));
                }
            } catch (Exception e) {
                Log.e(TAG, "Error while collect crash info", e);
            }
        }
    }

    @SuppressWarnings("static-access")
    @Override
    public void uncaughtException(Thread arg0, Throwable arg1) {
        if (debug) {
            String result = getError(arg1);
                WriteFileUtil.writeTxtToFile(result, StorageUtil.getPrimaryStoragePath(mContext), "log.d");
//            HandlerUtil.sendEmptymessage((Activity) mContext, new FunCallback() {
//                @Override
//                public void simpleRun(Object aty) {
//                    super.simpleRun(aty);
//                    ToastUtil.live((Activity) mContext).toast("应用报错，正在重启");
//                }
//            });
        System.exit(0);
//            new Thread() {
//                @Override
//                public void run() {
//                    super.run();
//                    Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
//                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//                    mContext.startActivity(i);
//                }
//            }.start();
        }

    }

    public static String getError(Throwable arg1) {
        String errorMsg = "界面： "
                + "\n";
        errorMsg += "原因：" + arg1.getMessage() + "\n" + "\n\n";
        String result = "";
        try {
            StackTraceElement[] eles = arg1.getStackTrace();
            for (int i = 0; i < eles.length; i++) {
                errorMsg += i + 1 + "：" + eles[i].toString() + "\n";
            }
            Logs.i("----- " + errorMsg);
            String emsg = ReadFileUtil.readsd(mContext, StorageUtil.getPrimaryStoragePath(mContext) + "/log.d");
            result = emsg + "\n" + errorMsg;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
    public static boolean errorDialog(Throwable t) {
        errorDialog(getError(t));
        return false;
    }
    public static boolean errorDialog(String out) {
        if(TextUtils.isEmpty(out)){
         out = ReadFileUtil.readsd(mContext, StorageUtil.getPrimaryStoragePath(mContext) + "/log.d");

        }
        Logs.i("---------- out " + out);
        if (out.equals("")) {
            return false;
        }
        SpannableStringBuilder spannable = new TextHighLightDecorator(
                Color.YELLOW).setMatcher(mContext.getPackageName())
                .getDecorated(out, out, out);
        DialogInfo dialogInfo = new DialogInfo(ActivityPool.currAty);
        dialogInfo.aty = ActivityPool.currAty;
        dialogInfo.message = spannable;
        dialogInfo.negativeButtonText = "发送";
        final String finalOut = out;
        dialogInfo.negativeButtonClickListener = new DialogUtil.DialogClicker() {

            @Override
            public void onClick(DialogInterface dialog, int arg1) {
                // TODO Auto-generated method stub
                if (finalOut != null && !finalOut.equals("")) {
                    Intent intent = new Intent(Intent.ACTION_SEND);
                    intent.putExtra(Intent.EXTRA_TEXT, new String(finalOut));
                    intent.setType("text/plain");
                    mContext.startActivity(Intent.createChooser(intent,
                            "分享").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                }
                super.onClick(dialog, arg1);

            }
        };
        DialogUtil.showChoiceDialog(dialogInfo, true).show();
        WriteFileUtil.writeTxtToFile("", StorageUtil.getPrimaryStoragePath(mContext), "log.d");
        return true;
    }
}